﻿using Microsoft.CSharp;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AgentSystem.AgentCreator.Util
{
    public class SimpleCodeCompiler
    {
        /// <summary>
        /// Compile Code received as string.
        /// </summary>
        /// <param name="sourceCode">C# code.</param>
        /// <returns>Success</returns>
        public static bool CompileCode(string sourceCode, string assemblyName, string[] referencedAssemblies,  bool asExecutable, ref string compilationException)
        {
            if(string.IsNullOrEmpty(assemblyName))
            {
                throw new ArgumentException("Assembly Name must not be null or empty!");
            }
            

            //Set output assembly name and type
            string outputAssembly = assemblyName + ".dll";
            if (asExecutable)
            {
                outputAssembly = assemblyName + ".exe";
            }

            //Set the compiler parameters
            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = asExecutable;
            parameters.OutputAssembly = outputAssembly;

            //Reference Runtime Serialization Assembly 
            parameters.ReferencedAssemblies.AddRange(referencedAssemblies);

            CompilerResults compilerResults = null;
            using (CodeDomProvider codeDomeProvider = CodeDomProvider.CreateProvider("C#"))
            {
                compilerResults = codeDomeProvider.CompileAssemblyFromSource(parameters, sourceCode);
            }

            if (compilerResults.Errors.Count > 0)
            {
                compilationException = BuildExceptionString(compilerResults.Errors);
                return false;
            }
            return true;
        }

        /// <summary>
        /// Compile Code received as string.
        /// </summary>
        /// <param name="sourceCode">C# code.</param>
        /// <returns>Success</returns>
        public static bool CompileCode(CodeCompileUnit compileUnit, string assemblyName, string[] referencedAssemblies, bool asExecutable, ref string compilationException)
        {
            if (string.IsNullOrEmpty(assemblyName))
            {
                throw new ArgumentException("Assembly Name must not be null or empty!");
            }


            //Set output assembly name and type
            string outputAssembly = assemblyName + ".dll";
            if (asExecutable)
            {
                outputAssembly = assemblyName + ".exe";
            }

            //Set the compiler parameters
            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = asExecutable;
            parameters.OutputAssembly = outputAssembly;

            //Reference Runtime Serialization Assembly 
            parameters.ReferencedAssemblies.AddRange(referencedAssemblies);

            CompilerResults compilerResults = null;
            using (CodeDomProvider codeDomeProvider = CodeDomProvider.CreateProvider("C#"))
            {
                compilerResults = codeDomeProvider.CompileAssemblyFromDom(parameters, compileUnit);
            }

            if (compilerResults.Errors.Count > 0)
            {
                compilationException = BuildExceptionString(compilerResults.Errors);
                return false;
            }
            return true;
        }

        /// <summary>
        /// Builds the exception string.
        /// </summary>
        /// <param name="compilationResults">The compilation results.</param>
        /// <returns></returns>
        public static string BuildExceptionString(CompilerErrorCollection errors)
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach (var error in errors)
            {
                stringBuilder.AppendLine(error.ToString());
            }
            return stringBuilder.ToString();
        }
    }
}
